﻿using System;
using System.Threading;

namespace HidLibrary
{
    internal class HidDeviceEventMonitor
    {
        public event InsertedEventHandler Inserted;
        public event RemovedEventHandler Removed;

        public delegate void InsertedEventHandler();
        public delegate void RemovedEventHandler();

        private readonly HidDevice _device;
        private readonly object _bus; // used for locking
        private bool _wasConnected;

        public HidDeviceEventMonitor(HidDevice device, object monitorBus)
        {
            _device = device;
            _bus = monitorBus;
        }

        private Action eventMonitor;
        private IAsyncResult eventMonitorInvocation;
        public void Init()
        {
            if (eventMonitor == null)
                eventMonitor = new Action(DeviceEventMonitor);
            eventMonitorInvocation = eventMonitor.BeginInvoke(DisposeDeviceEventMonitor, eventMonitor);
        }

        private bool shouldDie = false;
        public void Fini()
        {
            shouldDie = true;
        }

        private void DeviceEventMonitor()
        {
            Monitor.Enter(_bus);
            var isConnected = _device.IsConnected;

            if (isConnected != _wasConnected)
            {
                if (isConnected && Inserted != null) Inserted();
                else if (!isConnected && Removed != null) Removed();
                _wasConnected = isConnected;
            }
            else if (isConnected && Removed != null)
            {
                if (_device.Expire())
                    Removed();
            }

            Monitor.Wait(_bus, 1000);

            if (_device.MonitorDeviceEvents && !shouldDie)
                Init();
            shouldDie = false;
            Monitor.Exit(_bus);
        }

        private static void DisposeDeviceEventMonitor(IAsyncResult ar)
        {
            ((Action)ar.AsyncState).EndInvoke(ar);
        }
    }
}
